package com.mapfinal.style;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import com.jfinal.aop.Clear;
import com.jfinal.core.Controller;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.ehcache.CacheKit;
import com.lambkit.web.render.XmlFileRender;

public class StyleController extends Controller {

	public void index() {
		//style user guide.
	}
	/**
	 * 本地sld
	 * style/file/default
	 */
	public void file() {
		String name = getPara(0, "default");
		// 获取读取xml的对象。
		SAXReader sr = new SAXReader();
		String xmlinfo = "style is empty.";
		try {
			// 得到xml所在位置。然后开始读取。并将数据放入doc中
			Document doc = sr.read(PathKit.getWebRootPath() + "/static/sld/" + name + ".sld");
			xmlinfo = doc.asXML();
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		render(new XmlFileRender(xmlinfo));
	}

	/**
	 * 在线生成sld
	 * style/sld?nl=map:152201&n=XZQMC&r=8fbccf%2c0%2cff0000%2c2;%E7%BA%A2%E6%98%9F%E6%9D%91
	 */
	@Clear
	public void sld() {
		keepPara();
		renderSld();
	}
	
	/**
	 * 功能等同sld
	 * style/nl=map:152201@n=XZQMC@r=8fbccf,0,ff0000,2;%E7%BA%A2%E6%98%9F%E6%9D%91
	 */
	@Clear
	public void ags() {
		// int prjid = getParaToInt("prjid", 1);
		// String layer = getPara("layer", "csus:landplan");
		// renderText("This function has not been implemented on this
		// platform.");
		String param = getPara(0, getPara("sld"));
		// System.out.println(param);
		// 缓存名称
		String cachename = null;
		// 图形类型
		String maptype = "polygon";// getPara("mt", "polygon");
		// 是否更新缓存
		String nc = null;// getPara("nc");
		// 返回格式
		String at = "xml";// getPara("at", "xml");
		// 图层名称
		String nl = "default"; // getPara("nl", "default");
		// 样式名称
		String ul = "default"; // getPara("ul", "default");
		// String prjid = getPara("prjid");
		String pname = "classtype";// getPara("n", "classtype");
		String filterPara = null;// getPara("filter");//添加and,or条件
		// 文件名称
		String name = "default"; // getPara("f", "default");
		//
		String charset = "UTF-8";// "GB2312"
		// 具体样式
		String filterprop = null;// getPara("r");//,
									// "10519D,0.2;水域,林地-666666,0.2;农田");
		String pt = "circle";// getPara("pt", "circle");

		if (StrKit.notBlank(param)) {
			String[] params = param.split("@");
			for (String p : params) {
				// System.out.println("param @ " + p);
				if (p.startsWith("c=") || p.startsWith("C=")) {
					cachename = p.substring(2);
				} else if (p.startsWith("mt=") || p.startsWith("MT=")) {
					maptype = p.substring(3);
				} else if (p.startsWith("nc=") || p.startsWith("NC=")) {
					nc = p.substring(3);
				} else if (p.startsWith("at=") || p.startsWith("AT=")) {
					at = p.substring(3);
				} else if (p.startsWith("nl=") || p.startsWith("NL=")) {
					nl = p.substring(3);
				} else if (p.startsWith("ul=") || p.startsWith("UL=")) {
					ul = p.substring(3);
				} else if (p.startsWith("n=") || p.startsWith("N=")) {
					pname = p.substring(2);
				} else if (p.startsWith("filter=") || p.startsWith("FILTER=")) {
					filterPara = p.substring(7);
				} else if (p.startsWith("f=") || p.startsWith("F=")) {
					name = p.substring(2);
				} else if (p.startsWith("r=") || p.startsWith("R=")) {
					filterprop = p.substring(2);
				} else if (p.startsWith("charset=") || p.startsWith("CHARSET=")) {
					charset = p.substring(8);
				} else if (p.equalsIgnoreCase("pt=") || p.startsWith("PT=")) {
					pt = p.substring(3);
					setAttr("pt", pt);
				}
			}
		}
		setAttr("c", cachename);
		setAttr("mt", maptype);
		setAttr("nc", nc);
		setAttr("at", at);
		setAttr("charset", charset);
		setAttr("nl", nl);
		setAttr("ul", ul);
		setAttr("n", pname);
		setAttr("filter", filterPara);
		setAttr("r", filterprop);
		setAttr("f", name);
		setAttr("pt", pt);
		renderSld();
	}

	private void renderSld() {
		// 缓存名称
		String cachename = getAttr("c");
		System.out.println("cache name is : " + cachename);
		// 图形类型
		String maptype = getAttr("mt", "polygon");
		setAttr("pt", getAttr("pt", "circle"));
		// 是否更新缓存
		String nc = getAttr("nc");
		// 返回格式
		String at = getAttr("at", "xml");
		// geoserver的时候使用UTF-8，ArcGIS的时候使用GB2312
		String charset = getAttr("charset", "UTF-8");// "GB2312"
		// 图层名称
		// Geoserver和ArcGIS的nl=layer_name图层名称
		String nl = getAttr("nl", "default");
		// 样式名称
		// ArcGIS的ul=style_name样式名称
		String ul = getAttr("ul", "default");
		// String prjid = getAttr("prjid");
		String pname = getAttr("n", "classtype");
		// 添加and,or条件
		String filterPara = getAttr("filter");
		// 具体样式
		String filterprop = getAttr("r");// , "10519D,0.2;水域,林地-666666,0.2;农田");
		// 文件名称
		String name = getAttr("f", "default");
		/*
		 * System.out.println("n=" + pname); 
		 * System.out.println("nl=" + nl);
		 * System.out.println("ul=" + ul); 
		 * System.out.println("nc=" + nc);
		 * System.out.println("at=" + at); 
		 * System.out.println("r=" + filterprop);
		 */
		if (!StrKit.notBlank(nc) || nc.equalsIgnoreCase("false")) {
			if (StrKit.notBlank(cachename) && at.equalsIgnoreCase("xml")) {
				String cinfo = CacheKit.get("ehCacheMapData", cachename);
				if (StrKit.notBlank(cinfo)) {
					render(new XmlFileRender(cinfo));
					return;
				}
			}
		}

		System.out.println("create new sld...");
		Document document = DocumentHelper.createDocument();
		Element root = document.addElement("sld:StyledLayerDescriptor");
		root.addAttribute("xmlns", "http://www.opengis.net/sld");
		root.add(new Namespace("sld", "http://www.opengis.net/sld"));
		root.add(new Namespace("ogc", "http://www.opengis.net/ogc"));
		root.add(new Namespace("gml", "http://www.opengis.net/gml"));
		root.addAttribute("version", "1.0.0");

		Element row_nl = root.addElement("sld:NamedLayer");
		row_nl.addElement("sld:Name").addText(nl);
		Element row_nl_us = row_nl.addElement("sld:UserStyle");
		row_nl_us.addElement("sld:Name").addText(ul);
		Element row_nl_us_f = row_nl_us.addElement("sld:FeatureTypeStyle");

		if (StrKit.notBlank(filterprop)) {
			String[] listfilter = filterprop.split("-");
			if (listfilter.length > 0) {
				for (String filter : listfilter) {
					String[] finfo = filter.split(";");
					if (finfo.length > 1) {
						Element row_nl_us_r = row_nl_us_f.addElement("sld:Rule");
						addRule(row_nl_us_r, maptype, pname, finfo[0], finfo[1], filterPara);
					}
				}
			}
		} else if (StrKit.notBlank(filterPara)) {
			Element row_nl_us_r = row_nl_us_f.addElement("sld:Rule");
			addRule(row_nl_us_r, maptype, pname, "10519D", null, filterPara);
		}

		if (at.equalsIgnoreCase("xml")) {
			String xmlinfo = formatXML(document, charset);// document.asXML();//
			// System.out.println(xmlinfo);
			if (StrKit.notBlank(cachename))
				CacheKit.put("ehCacheMapData", cachename, xmlinfo);
			// if(StrKit.notBlank(cachename) && StrKit.notBlank(nc) &&
			// nc.equalsIgnoreCase("true")) {}
			render(new XmlFileRender(xmlinfo));
		} else {
			// String name = getAttr("f", "default");
			saveDocument(document, PathKit.getWebRootPath() + "/static/sld/" + name + ".sld", charset);
			if (at.equalsIgnoreCase("json")) {
				setAttr("flag", true);
				setAttr("res", "/static/sld/" + name + ".sld");
				renderJson();
			} else if (at.equalsIgnoreCase("text"))
				renderText("true,/static/sld/" + name + ".sld");
			else
				renderJson(true);
		}
	}

	private void addRule(Element row, String maptype, String pname, String color, String filterprop,
			String filterPara) {
		Element row_nl_us_r_f = row.addElement("ogc:Filter");

		if (StrKit.notBlank(filterprop)) {
			Element row_nl_us_r_a = null;
			if (StrKit.notBlank(filterPara)) {
				row_nl_us_r_a = row_nl_us_r_f.addElement("ogc:And");
				boolean bOr = filterPara.startsWith("@") ? true : false;
				if (bOr)
					filterPara = filterPara.substring(1);
				String[] andParasArray = filterPara.split(";");
				for (String str : andParasArray) {
					if (StrKit.notBlank(str)) {
						String[] para = str.split(",");
						if (para.length == 2) {
							String name = para[0];
							String val = para[1];
							if (bOr) {
								Element filter_ogc = row_nl_us_r_a.addElement("ogc:And");
								setFilter(filter_ogc, name, val);
							} else {
								setFilter(row_nl_us_r_a, name, val);
							}
						} else if (para.length == 3) {
							String ao = para[0];
							String name = para[1];
							String val = para[2];
							if (bOr) {
								if ("or".equalsIgnoreCase(ao)) {
									Element filter_ogc = row_nl_us_r_a.addElement("ogc:Or");
									setFilter(filter_ogc, name, val);
								} else {
									Element filter_ogc = row_nl_us_r_a.addElement("ogc:And");
									setFilter(filter_ogc, name, val);
								}
							} else {
								setFilter(row_nl_us_r_a, name, val);
							}
						}
					} // if
				} // for
			} else {
				row_nl_us_r_a = row_nl_us_r_f;
			}

			String[] listfilter = filterprop.split(",");
			if (listfilter.length == 1) {
				setFilter(row_nl_us_r_a, pname, filterprop);
			}
			if (listfilter.length > 1) {
				Element row_nl_us_r_o = row_nl_us_r_a.addElement("ogc:Or");
				for (String filter : listfilter) {
					setFilter(row_nl_us_r_o, pname, filter);
				}
			}
		} else {
			String[] andParasArray = filterPara.split(";");
			for (String str : andParasArray) {
				if (StrKit.notBlank(str)) {
					String[] para = str.split(",");
					String name = para[0];
					String val = para[1];
					setFilter(row_nl_us_r_f, name, val);
				}
			}
		}

		if (maptype.equals("point")) {
			Element row_nl_us_r_p = row.addElement("sld:PointSymbolizer");
			Element rowG = row_nl_us_r_p.addElement("Graphic");
			Element rowM = rowG.addElement("Mark");
			Element rowWk = rowM.addElement("WellKnownName");
			rowWk.addText(getAttr("pt").toString());
			Element rowF = rowM.addElement("Fill");
			String[] colors = color.split(",");
			if (colors.length > 0)
				rowF.addElement("CssParameter").addText("#" + colors[0]).addAttribute("name", "fill");
			if (colors.length > 1)
				rowF.addElement("CssParameter").addText(colors[1]).addAttribute("name", "fill-opacity");
		} else if (maptype.equals("line")) {
			Element row_nl_us_r_p = row.addElement("sld:LineSymbolizer");
			Element row_nl_us_r_p_s = row_nl_us_r_p.addElement("Stroke");
			String[] colors = color.split(",");
			if (colors.length > 0)
				row_nl_us_r_p_s.addElement("CssParameter").addText("#" + colors[0]).addAttribute("name", "stroke");
			else
				row_nl_us_r_p_s.addElement("CssParameter").addText("#FFFFFF").addAttribute("name", "stroke");
			if (colors.length > 1)
				row_nl_us_r_p_s.addElement("CssParameter").addText(colors[1]).addAttribute("name", "stroke-width");
			else
				row_nl_us_r_p_s.addElement("CssParameter").addText("0.5").addAttribute("name", "stroke-width");
		} else {
			Element row_nl_us_r_p = row.addElement("sld:PolygonSymbolizer");
			Element row_nl_us_r_p_f = row_nl_us_r_p.addElement("Fill");
			String[] colors = color.split(",");
			if (colors.length > 0)
				row_nl_us_r_p_f.addElement("CssParameter").addText("#" + colors[0]).addAttribute("name", "fill");
			if (colors.length > 1)
				row_nl_us_r_p_f.addElement("CssParameter").addText(colors[1]).addAttribute("name", "fill-opacity");
			Element row_nl_us_r_p_s = row_nl_us_r_p.addElement("Stroke");
			if (colors.length > 2)
				row_nl_us_r_p_s.addElement("CssParameter").addText("#" + colors[2]).addAttribute("name", "stroke");
			else
				row_nl_us_r_p_s.addElement("CssParameter").addText("#FFFFFF").addAttribute("name", "stroke");
			if (colors.length > 3)
				row_nl_us_r_p_s.addElement("CssParameter").addText(colors[3]).addAttribute("name", "stroke-width");
			else
				row_nl_us_r_p_s.addElement("CssParameter").addText("0.5").addAttribute("name", "stroke-width");
		}

	}

	private void setFilter(Element row, String pname, String filterprop) {
		Element row_nl_us_r_o = row.addElement("ogc:PropertyIsEqualTo");
		row_nl_us_r_o.addElement("ogc:PropertyName").addText(pname);
		String str = "";
		try {
			str = URLDecoder.decode(filterprop, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		row_nl_us_r_o.addElement("ogc:Literal").addText(str);
	}

	/**
	 * 格式化XML文档
	 * 
	 * @param document
	 *            xml文档
	 * @param charset
	 *            字符串的编码
	 * @return 格式化后XML字符串
	 */
	private String formatXML(Document document, String charset) {
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding(charset);
		StringWriter sw = new StringWriter();
		XMLWriter xw = new XMLWriter(sw, format);
		try {
			xw.write(document);
			xw.flush();
			xw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return sw.toString();
	}

	/**
	 * 保存XML文档
	 * 
	 * @param doc
	 * @throws IOException
	 */
	private void saveDocument(Document doc, String path, String charset) {
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding(charset);
		XMLWriter writer;
		try {
			writer = new XMLWriter(new FileOutputStream(path), format);
			writer.write(doc);
			writer.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
